package com.itcv.spring.security.demo.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.io.PrintWriter;

@Configuration
@EnableWebSecurity // 启用Spring Security的Web安全支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {


	/**
	 * 登录处理
	 * @param http
	 * @throws Exception
	 */
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 开启登录配置
		http.authorizeRequests()
				// 标识访问 `/index` 这个接口，需要具备`ADMIN`角色
				.antMatchers("/index").hasRole("ADMIN")
				// 允许匿名的url - 可理解为放行接口 - 多个接口使用,分割
				.antMatchers("/", "/home").permitAll()
				// 其余所有请求都需要认证
				.anyRequest().authenticated().and().formLogin()
				//.and()
				// 设置登录认证页面
				//.formLogin().loginPage("/login")
				// 登录成功后的处理接口 - 方式①
				//.loginProcessingUrl("/home")
				// 自定义登陆用户名和密码属性名，默认为 username和password
				//.usernameParameter("username")
				//.passwordParameter("password")
				// 登录成功后的处理器  - 方式②
//                .successHandler((req, resp, authentication) -> {
//                    resp.setContentType("application/json;charset=utf-8");
//                    PrintWriter out = resp.getWriter();
//                    out.write("登录成功...");
//                    out.flush();
//                })
				// 配置登录失败的回调
				.failureHandler((req, resp, exception) -> {
					resp.setContentType("application/json;charset=utf-8");
					PrintWriter out = resp.getWriter();
					out.write("登录失败...");
					out.flush();
				})
				.permitAll()//和表单登录相关的接口统统都直接通过
				.and()
				.logout().logoutUrl("/logout")
				// 配置注销成功的回调
				.logoutSuccessHandler((req, resp, authentication) -> {
					resp.setContentType("application/json;charset=utf-8");
					PrintWriter out = resp.getWriter();
					out.write("注销成功...");
					out.flush();
				})
				.permitAll()
				.and()
				.httpBasic()
				.and()
				// 关闭CSRF跨域
				.csrf().disable();

	}

	/**
	 * 忽略拦截
	 * @param web
	 * @throws Exception
	 */
	@Override
	public void configure(WebSecurity web) throws Exception {
		// 设置拦截忽略url - 会直接过滤该url - 将不会经过Spring Security过滤器链
		web.ignoring().antMatchers("/getUserInfo");
		// 设置拦截忽略文件夹，可以对静态资源放行
		web.ignoring().antMatchers("/css/**", "/js/**");
	}


	/**
	 * 将用户设置在内存中
	 * @param auth
	 * @throws Exception
	 */
	@Autowired
	public void config(AuthenticationManagerBuilder auth) throws Exception {
		// 在内存中配置用户，配置多个用户调用`and()`方法
		auth.inMemoryAuthentication()
				.passwordEncoder(passwordEncoder()) // 指定加密方式
				.withUser("admin").password(passwordEncoder().encode("123456")).roles("ADMIN")
				.and()
				.withUser("test").password(passwordEncoder().encode("123456")).roles("USER");
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		// BCryptPasswordEncoder：Spring Security 提供的加密工具，可快速实现加密加盐
		return new BCryptPasswordEncoder();
	}

}
